package org.colafries.admin.querybuilder.indexQuery;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.colafries.admin.entity.vo.index.DerivativeIndexDTO;
import org.colafries.admin.exceptions.ServiceException;
import org.colafries.admin.exceptions.enums.ErrorCodeEnum;
import org.colafries.admin.querybuilder.entity.AggFunctionContext;
import org.colafries.admin.querybuilder.entity.IndexQueryParamContext;
import org.colafries.admin.querybuilder.entity.IndexQuerySqlBuildContext;
import org.colafries.admin.querybuilder.utils.SqlSegmentBuilderUtil;
import org.colafries.common.enums.AggFunctionEnum;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Ann
 * @version v1.0
 * @ClassName IndexQueryDerivativeIndexBuilder
 * @Description
 * @date Created in 2024/6/20
 **/
@Slf4j
public class DerivativeIndexBuilder implements IndexQuerySqlSegmentBuilder {


    @Override
    public void buildQueryParma(IndexQueryParamContext queryParamContext) {

    }

    @Override
    public void buildQuery(IndexQueryParamContext queryParamContext, IndexQuerySqlBuildContext sqlBuildContext) {
        queryParamContext.getDerivativeIndexDTOList().forEach(derivativeIndexDTO -> {
            // 派生指标表达式
            String expression = buildExpression(derivativeIndexDTO, queryParamContext);
            // select columns
            sqlBuildContext.getSelectColumns().add(expression);
        });
    }

    /**
     * <p>构建派生指标表达式</p>
     * <p>表达式格式：</p>
     * <b>原子指标.聚合函数(CASE WHEN 业务限定表达式 THEN 原子指标转换后的表达式 ELSE NULL/0 END) 派生指标.field</b>
     *
     * @param derivativeIndexDTO
     * @return java.lang.String
     * @Author anning
     * @Date 2024/6/20
     */
    private String buildExpression(DerivativeIndexDTO derivativeIndexDTO, IndexQueryParamContext queryParamContext) {
        // 业务限定表达式
        String conditionExp = buildConditionExp(derivativeIndexDTO.getConditionDTOList(), queryParamContext);
        String atomicMetricExp = derivativeIndexDTO.getAtomicMetricDTO().getExpression();
        // 解析原子指标表达式
        AggFunctionContext aggFunctionContext = SqlSegmentBuilderUtil.parseAggFunctionExp(atomicMetricExp);
        if (aggFunctionContext == null) {
            log.warn("原子指标表达式解析失败 atomicMetricCode {},表达式 {}", derivativeIndexDTO.getAtomicMetricDTO().getCode(), atomicMetricExp);
            throw new ServiceException(ErrorCodeEnum.GL999999, "原子指标表达式解析失败");
        }
        // 原子指标中的聚合函数
        String aggFunction = aggFunctionContext.getAggFunction().toUpperCase();
        // 原子指标表达式中的列 {key}
        String atomicIdxColumnExp = aggFunctionContext.getColumnExpression();
        // 原子指标表达式中的列(转换后) {key} --> {8489477722623512576}
        String atomicIdxColumnExpConverted = SqlSegmentBuilderUtil.convertExpression(atomicIdxColumnExp, queryParamContext.getColumnExpMap());
        // 派生指标列表达式
        String defaultValueExp = "";
        if (AggFunctionEnum.COUNT.getSymbol().equals(aggFunction)) {
            // COUNT
            defaultValueExp = "NULL";
        } else if (AggFunctionEnum.SUM.getSymbol().equals(aggFunction)) {
            // SUM
            defaultValueExp = "0";
        }
        // 构建列表达式
        String columnExpression = Strings.isEmpty(conditionExp) ?
                atomicIdxColumnExpConverted : String.format("CASE WHEN %s THEN %s ELSE %s END", conditionExp, atomicIdxColumnExpConverted, defaultValueExp);
        // 聚合函数(派生指标列表达式)
        return String.format("%s( %s ) AS %s", aggFunction, columnExpression, derivativeIndexDTO.getField());
    }

    /**
     * 构建业务限定表达式
     *
     * @return java.lang.String
     * @Author anning
     * @Date 2024/6/20
     */
    private String buildConditionExp(List<DerivativeIndexDTO.LogicConditionDTO> conditionDTOList, IndexQueryParamContext queryParamContext) {
        if (CollectionUtils.isEmpty(conditionDTOList)) {
            return null;
        }
        // (业务限定1.expression) AND (业务限定2.expression) AND ... AND(业务限定N.expression)
        return conditionDTOList.stream()
                .map(conditionDTO -> {
                    Map<String, String> fieldExpMap = queryParamContext.getColumnExpMap();
                    String parsedExpression = SqlSegmentBuilderUtil.convertExpression(
                            conditionDTO.getExpression(), fieldExpMap
                    );
                    return String.format("(%s)", parsedExpression);
                })
                // 如果表达式为()，则过滤掉
                .filter(expression -> !expression.equals("()"))
                .collect(Collectors.joining(" AND "));
    }
}
